/* Play MP3 file from Flash(file system)

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"
#include "sdkconfig.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include <string.h>

#include "audio_error.h"
#include "audio_mem.h"

#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "i2s_stream.h"
#include "fatfs_stream.h"
#include "mp3_decoder.h"
#include "esp_audio.h"

#include "bsp_sdspi.h"

#include "audio_board_init.h"

// #define TAG  "audio_mp3"
 
static QueueHandle_t audio_queue = NULL;      // 队列

static audio_pipeline_handle_t pipeline;
static audio_event_iface_handle_t evt_handle;
static audio_element_handle_t fatfs_stream, i2s_stream, mp3_decoder;

esp_err_t get_i2s_pins(i2s_port_t port, i2s_pin_config_t *i2s_config)
{
    #ifdef TAG
    AUDIO_NULL_CHECK(TAG, i2s_config, return ESP_FAIL);
    #endif
    if (port == I2S_NUM_0) {
        i2s_config->bck_io_num = I2S_BCK_IO;
        i2s_config->ws_io_num = I2S_WS_IO;
        i2s_config->data_out_num = I2S_DO_IO;
        i2s_config->data_in_num = I2S_DI_IO;
        i2s_config->mck_io_num = I2S_MCK_IO;
    } else if (port == I2S_NUM_1) {
        i2s_config->bck_io_num = -1;
        i2s_config->ws_io_num = -1;
        i2s_config->data_out_num = -1;
        i2s_config->data_in_num = -1;
        i2s_config->mck_io_num = -1;
    } else {
        memset(i2s_config, -1, sizeof(i2s_pin_config_t));
        #ifdef TAG
        ESP_LOGE(TAG, "i2s port %d is not supported", port);
        #endif
        return ESP_FAIL;
    }

    return ESP_OK;
}

esp_err_t i2s_mclk_gpio_select(i2s_port_t i2s_num, gpio_num_t gpio_num)
{
    return ESP_OK;
}

#if 0   // =====================================
void audio_pipeline_del_destroy(void)
{
    ESP_LOGI(TAG, "[ 7 ] Stop audio_pipeline");
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);

    audio_pipeline_unregister(pipeline, fatfs_stream);
    audio_pipeline_unregister(pipeline, i2s_stream);
    audio_pipeline_unregister(pipeline, mp3_decoder);

    /* Terminal the pipeline before removing the listener */
    audio_pipeline_remove_listener(pipeline);

    /* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface */
    audio_event_iface_destroy(evt_handle);

    /* Release all resources */
    audio_pipeline_deinit(pipeline);
    audio_element_deinit(fatfs_stream);
    audio_element_deinit(i2s_stream);
    audio_element_deinit(mp3_decoder);
}
#endif
 
static int audio_music_play(play_info_t play_info)
{
    if (audio_queue == NULL) return false;
    return xQueueSend(audio_queue, &play_info, (TickType_t)0);   
}

void audio_music_play_audio(uint8_t music)
{
    play_info_t play_info;
    play_info.music = music;
    play_info.file  = AUDIO_FILE;
    play_info.ctrl  = AUDIO_CTRL_PLAY;
    audio_music_play(play_info);
}

void audio_music_play_ctrl(audio_ctrl_t ctrl)
{
    play_info_t play_info;
    play_info.file = MP3_FILE;
    play_info.ctrl = ctrl;
    audio_music_play(play_info);
}

void audio_music_play_mp3(uint8_t music)
{
    play_info_t play_info;
    play_info.music = music;
    play_info.file  = MP3_FILE;
    play_info.ctrl  = AUDIO_CTRL_PLAY;
    audio_music_play(play_info);
}

static int mp3_target_volume = 0;  // 目标音量

void audio_music_set_volume(uint8_t volume)
{
    mp3_target_volume = volume / 2;  // 音量范围0~50； 太大会破音
    #ifdef TAG
    ESP_LOGI(TAG, "[ * ] Volume set_handle to %d %%", volume);
    #endif
}

uint8_t audio_music_get_volume(void)
{
    return mp3_target_volume;
}

extern void app_music_lvgl_name_text(const char *name);

static void audio_paly_mp3_task(void *arg)
{
    uint8_t audio_music = 0;  
    play_info_t play_info;  
    audio_event_iface_msg_t msg;
    audio_element_state_t el_state = 0;
    #ifdef TAG
    ESP_LOGI(TAG, "audio_paly_mp3_task start...");
    #endif
    #define MP3_MUSIC_NONE  0XFF   // MP3无效音频
    uint8_t mp3_music_index = MP3_MUSIC_NONE;      // 正在播放第几首MP3音乐文件
    bool mp3_is_regain = 0;         // 1: 需要恢复播放
    audio_element_info_t fatfs_info;
 
    int mp3_temp_volume = 0;

    while ( true ) {
        if (xQueueReceive(audio_queue, &play_info, 100) == pdTRUE) {
            #ifdef TAG
            ESP_LOGI(TAG, "[ * ] AUDIO_CTRL_PLAY el_state = %d", el_state);
            #endif 
            bool audio_new_play = false;  // 1: 使能播放新音频文件
            switch (play_info.ctrl) {
            case AUDIO_CTRL_RUNNING:    /* 正在播放 */ 
                if (el_state == AEL_STATE_PAUSED) {
                    audio_pipeline_resume(pipeline);  
                } else if (mp3_music_index == MP3_MUSIC_NONE) {  // 开始啥都没有播放
                    mp3_music_index = 0;  // 从第一首开始播放
                    audio_new_play = true;
                } else {
                    mp3_is_regain = true;   // 使能继续播放
                    mp3_temp_volume = 1;    // 起始临时音量
                    audio_new_play = true;
                } 
                #ifdef TAG
                ESP_LOGI(TAG, "[ * ] AUDIO_CTRL_RUNNING");
                #endif
                break;
            case AUDIO_CTRL_PAUSED:     /* 暂停播放 */
                if (el_state == AEL_STATE_RUNNING) {
                    audio_pipeline_pause(pipeline);
                    mp3_is_regain = false;  // 不允许继续播放
                }
                #ifdef TAG
                ESP_LOGI(TAG, "[ * ] AUDIO_CTRL_PAUSED");
                #endif
                break;
            case AUDIO_CTRL_PLAY:       /* 播放指定一首 */
                if (play_info.file == AUDIO_FILE) {
                    audio_music = play_info.music;
                } else {
                    mp3_music_index = play_info.music;
                    fatfs_info.byte_pos = 0;
                }
                audio_new_play = true;
                break;
            case AUDIO_CTRL_NEXT:       /* 下一首 */
                if (mp3_music_index < 11) mp3_music_index++;
                fatfs_info.byte_pos = 0;
                audio_new_play = true;
                break;
            case AUDIO_CTRL_LAST:       /* 上一首 */
                if (mp3_music_index > 0) mp3_music_index--;
                audio_new_play = true;
                fatfs_info.byte_pos = 0;
                break; 
            default:
                break;
            }
 
            if (audio_new_play == false) {
                continue;
            }

            /* 1、先暂停pipeline */
            if (el_state == AEL_STATE_RUNNING) { //} || 
                // el_state == AEL_STATE_PAUSED) { // 先判断是否处于暂停状态！
                if (play_info.file == AUDIO_FILE && mp3_music_index != MP3_MUSIC_NONE) {  // 如果此时正在播放MP3音乐，被语音提示音打断了
                    audio_element_getinfo(fatfs_stream, &fatfs_info);  // 记录当前mp3的播放信息
                    if (el_state == AEL_STATE_RUNNING) { 
                        mp3_is_regain = true;   // 如果此时正在播放MP3，需要使能恢复功能！
                    } 
                }
                audio_pipeline_stop(pipeline);  
                audio_pipeline_wait_for_stop(pipeline);
                audio_pipeline_terminate(pipeline);
            }
            /* 2、设置需要播放的音频URL路径 */
            const char *audio_file = NULL;  // "/sdcard/MP3/001开机声.mp3";
            if (play_info.file == AUDIO_FILE) {
                audio_file = MOUNT_POINT"/AUDIO";  // "/sdcard/AUDIO"
                i2s_stream_set_clk(i2s_stream, 16000, 16, I2S_CHANNEL_MONO);  // 特殊处理：语音提示就固定为这个波特率
            } else {   // MP3_FILE
                audio_file = MOUNT_POINT"/MP3";   // "/sdcard/MP3"
                audio_music = mp3_music_index;
            }

            const char *audio_url = NULL; 
            do {
                audio_url = fat_open_audio_name(audio_file, audio_music);
                if (audio_url == NULL) {  // 如果没找到，说明索引超了
                    audio_music = 0; // 自动从0索引开始！
                }
            } while (audio_url == NULL);

            #ifdef TAG
            ESP_LOGI(TAG, "[ * ] music_name[%d]: %s", audio_music, audio_url);
            #endif
            audio_element_set_uri(fatfs_stream, audio_url);

            if (play_info.file == MP3_FILE) {
                app_music_lvgl_name_text(audio_url);
            }

            /* 支持语音提示打断后，继续重播！ */
            if (play_info.file == MP3_FILE && mp3_is_regain == true && fatfs_info.byte_pos > 0) {
                mp3_is_regain = false; 
                audio_element_setinfo(fatfs_stream, &fatfs_info);  // 设置原来音乐的info信息，以恢复播放
                #ifdef TAG
                ESP_LOGI(TAG, "[ * ] fatfs_info=%lld/%lld", fatfs_info.byte_pos, fatfs_info.total_bytes);
                #endif
            }

            /* 3、复位pipeline，重新启动pipeline */
            audio_event_iface_discard(evt_handle);  // Discard all ongoing event message
            audio_pipeline_reset_ringbuffer(pipeline);
            audio_pipeline_reset_elements(pipeline);
            audio_pipeline_change_state(pipeline, AEL_STATE_INIT); 
            audio_pipeline_run(pipeline);
        }

        /* 音量渐变 */
        if (mp3_temp_volume > mp3_target_volume) {
            mp3_temp_volume--; 
        } else if (mp3_temp_volume < mp3_target_volume) {
            mp3_temp_volume++;
        }
        if (mp3_temp_volume != mp3_target_volume) {
            i2s_alc_volume_set(i2s_stream, mp3_temp_volume);  // i2s_strean.c ->  _i2s_write()  第 252行需要修改
        }

        /** audio监听事件 */
        esp_err_t ret = audio_event_iface_listen(evt_handle, &msg, 500);  // portMAX_DELAY
        if (ret != ESP_OK) {
            continue;
        }

        if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) mp3_decoder
            && msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO) {
            audio_element_info_t music_info;
            audio_element_getinfo(mp3_decoder, &music_info);
            #ifdef TAG
            ESP_LOGI(TAG, "[ * ] duration=%d,sample_rates=%d, bits=%d, ch=%d, bps=%d", music_info.duration,
                     music_info.sample_rates, music_info.bits, music_info.channels, music_info.bps);
            #endif
            if (play_info.file == MP3_FILE || music_info.channels == 2) {
                i2s_stream_set_clk(i2s_stream, music_info.sample_rates, music_info.bits, music_info.channels);
            } 
            audio_element_setinfo(i2s_stream, &music_info);
            continue;
        }

        /* Stop when the last pipeline element (i2s_stream in this case) receives stop play_info */
        if (msg.source == (void *) i2s_stream && msg.cmd == AEL_MSG_CMD_REPORT_STATUS) {
            el_state = audio_element_get_state(i2s_stream); // 记录当前的播放状态 
            if (el_state == AEL_STATE_FINISHED) {  // 播放完成！
                if (mp3_is_regain == true) { // 自动恢复播放mp3
                    audio_music_play_ctrl(AUDIO_CTRL_RUNNING);
                } else if (play_info.file == MP3_FILE) {
                    audio_music_play_ctrl(AUDIO_CTRL_NEXT);  // 下一首
                }
            } else if (el_state == AEL_STATE_STOPPED) { // 说明出现了错误！
                // 实测发现：播放MP3处于AEL_STATE_PAUSED时，播放语音提示音会出错！
                audio_music_play_audio(audio_music); // 重新播放
            }
            #ifdef TAG
            ESP_LOGI(TAG, "[ * ] audio_element_get_state: %d", el_state);
            #endif
        }
    }
    vTaskDelete(NULL);
}
 
// 初始化esp-adf音频框架
void audio_adf_init(void)
{
    // esp_log_level_set("*", ESP_LOG_WARN);
    esp_log_level_set("AUDIO_PIPELINE", ESP_LOG_WARN);
    esp_log_level_set("AUDIO_ELEMENT", ESP_LOG_WARN);
    esp_log_level_set("AUDIO_EVENT", ESP_LOG_WARN);
    esp_log_level_set("FATFS_STREAM", ESP_LOG_WARN);
    esp_log_level_set("MP3_DECODER", ESP_LOG_WARN);
    esp_log_level_set("I2S_STREAM", ESP_LOG_WARN);
    
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline = audio_pipeline_init(&pipeline_cfg);
    #ifdef TAG
    AUDIO_NULL_CHECK(TAG, pipeline, return);
    #endif
    fatfs_stream_cfg_t fatfs_cfg = FATFS_STREAM_CFG_DEFAULT();
    fatfs_cfg.type = AUDIO_STREAM_READER;
    fatfs_stream = fatfs_stream_init(&fatfs_cfg);

    i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg.i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
    i2s_cfg.use_alc = false;   // true: 使能回音效果 
    i2s_cfg.volume = 5;  // 如果解码IC，支持I2C设置音量，这个变量一定为0！
    i2s_stream = i2s_stream_init(&i2s_cfg);  
    // i2s_stream_set_clk(i2s_stream, i2s_cfg.i2s_config.sample_rate, i2s_cfg.i2s_config.bits_per_sample, I2S_CHANNEL_MONO);

    mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG();
    mp3_decoder = mp3_decoder_init(&mp3_cfg);

    audio_pipeline_register(pipeline, fatfs_stream, "file");
    audio_pipeline_register(pipeline, mp3_decoder, "mp3");
    audio_pipeline_register(pipeline, i2s_stream, "i2s");

    #ifdef TAG
    ESP_LOGI(TAG, "[3.5] Link it together [flash]-->file-->mp3_decoder-->i2s_stream-->[codec_chip]");
    #endif
    const char *link_tag[3] = {"file", "mp3", "i2s"};
    audio_pipeline_link(pipeline, &link_tag[0], 3);

    audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
    evt_handle = audio_event_iface_init(&evt_cfg);
    audio_pipeline_set_listener(pipeline, evt_handle);
 
    audio_queue = xQueueCreate(2, sizeof(play_info_t));
    xTaskCreatePinnedToCore(audio_paly_mp3_task, "audio_paly_mp3", 3 * 1024, NULL, 3, NULL, APP_CPU_NUM);  
    audio_music_set_volume(10);
    // audio_music_play_mp3(0);
#if 0 // test
    while ( true ) {
        vTaskDelay(3000);
        static uint8_t music = 0;
        // audio_music_play_mp3(music++);
        audio_music_play_audio(music++);
        if (music >= 4) music = 0;

        ESP_LOGI(TAG, "MALLOC_CAP_SPIRAM = %d, MALLOC_CAP_INTERNAL = %d", 
                heap_caps_get_free_size(MALLOC_CAP_SPIRAM), 
                heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
        vTaskDelay(6000); 
    }
#endif    
}
// 中文字体生成
// http://dz.lfly.xyz/forum.php?mod=viewthread&tid=72&extra=page%3D1
// LVGL 样式设计
// https://blog.csdn.net/qq_38685043/article/details/113616086
